<?php
/**
 * @package php-font-lib
 * @link    https://github.com/PhenX/php-font-lib
 * @author  Fabien Ménager <fabien.menager@gmail.com>
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
 * @version $Id: Font_Table_glyf.php 46 2012-04-02 20:22:38Z fabien.menager $
 */

namespace isszz\captcha\font\lib\glyph;

/**
 * Composite glyph outline
 *
 * @package php-font-lib
 */
class OutlineComposite extends Outline
{
	const ARG_1_AND_2_ARE_WORDS    = 0x0001;
	const ARGS_ARE_XY_VALUES       = 0x0002;
	const ROUND_XY_TO_GRID         = 0x0004;
	const WE_HAVE_A_SCALE          = 0x0008;
	const MORE_COMPONENTS          = 0x0020;
	const WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
	const WE_HAVE_A_TWO_BY_TWO     = 0x0080;
	const WE_HAVE_INSTRUCTIONS     = 0x0100;
	const USE_MY_METRICS           = 0x0200;
	const OVERLAP_COMPOUND         = 0x0400;

	/**
	 * @var OutlineComponent[]
	 */
	public $components = [];

	public function getGlyphIDs() {
		if (empty($this->components)) {
			$this->parseData();
		}

		$glyphIDs = [];
		foreach ($this->components as $_component) {
			$glyphIDs[] = $_component->glyphIndex;

			$_glyph   = $this->table->data[$_component->glyphIndex];

			if ($_glyph !== $this) {
				$glyphIDs = array_merge($glyphIDs, $_glyph->getGlyphIDs());
			}
		}

		return $glyphIDs;
	}

	/*function parse() {
		//$this->parseData();
	}*/

	public function parseData()
	{
		parent::parseData();

		$font = $this->getFont();

		do {
			$flags      = $font->readUInt16();
			$glyphIndex = $font->readUInt16();

			$a = 1.0;
			$b = 0.0;
			$c = 0.0;
			$d = 1.0;
			$e = 0.0;
			$f = 0.0;

			$point_compound  = null;
			$point_component = null;

			$instructions = null;

			if ($flags & self::ARG_1_AND_2_ARE_WORDS) {
				if ($flags & self::ARGS_ARE_XY_VALUES) {
					$e = $font->readInt16();
					$f = $font->readInt16();
				}
				else {
					$point_compound  = $font->readUInt16();
					$point_component = $font->readUInt16();
				}
			}
			else {
				if ($flags & self::ARGS_ARE_XY_VALUES) {
					$e = $font->readInt8();
					$f = $font->readInt8();
				}
				else {
					$point_compound  = $font->readUInt8();
					$point_component = $font->readUInt8();
				}
			}

			if ($flags & self::WE_HAVE_A_SCALE) {
				$a = $d = $font->readInt16();
			}
			elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) {
				$a = $font->readInt16();
				$d = $font->readInt16();
			}
			elseif ($flags & self::WE_HAVE_A_TWO_BY_TWO) {
				$a = $font->readInt16();
				$b = $font->readInt16();
				$c = $font->readInt16();
				$d = $font->readInt16();
			}

			$component                  = new OutlineComponent();
			$component->flags           = $flags;
			$component->glyphIndex      = $glyphIndex;
			$component->a               = $a;
			$component->b               = $b;
			$component->c               = $c;
			$component->d               = $d;
			$component->e               = $e;
			$component->f               = $f;
			$component->point_compound  = $point_compound;
			$component->point_component = $point_component;
			$component->instructions    = $instructions;

			$this->components[] = $component;
		} while ($flags & self::MORE_COMPONENTS);
	}

	public function encode()
	{
		$font = $this->getFont();

		$gids = $font->getSubset();

		$size = $font->writeInt16(-1);
		$size += $font->writeFWord($this->xMin);
		$size += $font->writeFWord($this->yMin);
		$size += $font->writeFWord($this->xMax);
		$size += $font->writeFWord($this->yMax);

		foreach ($this->components as $_i => $_component) {
			$flags = 0;
			if ($_component->point_component === null && $_component->point_compound === null) {
				$flags |= self::ARGS_ARE_XY_VALUES;

				if (abs($_component->e) > 0x7F || abs($_component->f) > 0x7F) {
					$flags |= self::ARG_1_AND_2_ARE_WORDS;
				}
			}
			elseif ($_component->point_component > 0xFF || $_component->point_compound > 0xFF) {
				$flags |= self::ARG_1_AND_2_ARE_WORDS;
			}

			if ($_component->b == 0 && $_component->c == 0) {
				if ($_component->a == $_component->d) {
					if ($_component->a != 1.0) {
						$flags |= self::WE_HAVE_A_SCALE;
					}
				}
				else {
					$flags |= self::WE_HAVE_AN_X_AND_Y_SCALE;
				}
			}
			else {
				$flags |= self::WE_HAVE_A_TWO_BY_TWO;
			}

			if ($_i < count($this->components) - 1) {
				$flags |= self::MORE_COMPONENTS;
			}

			$size += $font->writeUInt16($flags);

			$new_gid = array_search($_component->glyphIndex, $gids);
			$size += $font->writeUInt16($new_gid);

			if ($flags & self::ARG_1_AND_2_ARE_WORDS) {
				if ($flags & self::ARGS_ARE_XY_VALUES) {
					$size += $font->writeInt16($_component->e);
					$size += $font->writeInt16($_component->f);
				}
				else {
					$size += $font->writeUInt16($_component->point_compound);
					$size += $font->writeUInt16($_component->point_component);
				}
			}
			else {
				if ($flags & self::ARGS_ARE_XY_VALUES) {
					$size += $font->writeInt8($_component->e);
					$size += $font->writeInt8($_component->f);
				}
				else {
					$size += $font->writeUInt8($_component->point_compound);
					$size += $font->writeUInt8($_component->point_component);
				}
			}

			if ($flags & self::WE_HAVE_A_SCALE) {
				$size += $font->writeInt16($_component->a);
			}
			elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) {
				$size += $font->writeInt16($_component->a);
				$size += $font->writeInt16($_component->d);
			}
			elseif ($flags & self::WE_HAVE_A_TWO_BY_TWO) {
				$size += $font->writeInt16($_component->a);
				$size += $font->writeInt16($_component->b);
				$size += $font->writeInt16($_component->c);
				$size += $font->writeInt16($_component->d);
			}
		}

		return $size;
	}

	public function getSVGContours()
	{
		$contours = [];

		/** @var \FontLib\Table\Type\glyf $glyph_data */
		$glyph_data = $this->getFont()->getTableObject("glyf");

		/** @var Outline[] $glyphs */
		$glyphs = $glyph_data->data;

		foreach ($this->components as $component) {
			$_glyph = $glyphs[$component->glyphIndex];

			if ($_glyph !== $this) {
				$contours[] = [
					"contours"  => $_glyph->getSVGContours(),
					"transform" => $component->getMatrix(),
				];
			}
		}

		return $contours;
	}
}